package com.weishi.project.training.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weishi.common.utils.DataAnalysisUtils;
import com.weishi.common.utils.DateUtils;
import com.weishi.common.utils.StringUtils;
import com.weishi.project.speedometer.vo.PropellerFrequencyData;
import com.weishi.project.speedometer.vo.PropellerFrequencyDataVo;
import com.weishi.project.speedometer.vo.RealTimeDataVo;
import com.weishi.project.training.domain.HeartRateCount;
import com.weishi.project.training.domain.ShipSpeedRecord;
import com.weishi.project.training.domain.ShipSpeedRecordLog;
import com.weishi.project.training.domain.TrainingGroupChannel;
import com.weishi.project.training.mapper.ShipSpeedRecordMapper;
import com.weishi.project.training.service.IHeartRateCountService;
import com.weishi.project.training.service.IShipSpeedRecordLogService;
import com.weishi.project.training.service.IShipSpeedRecordService;
import com.weishi.project.training.service.ITrainingGroupChannelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 船速仪历史数据Service业务层处理
 */
@Service
public class ShipSpeedRecordServiceImpl extends ServiceImpl<ShipSpeedRecordMapper, ShipSpeedRecord> implements IShipSpeedRecordService {

    @Autowired
    private ShipSpeedRecordMapper shipSpeedRecordMapper;

    @Autowired
    private IShipSpeedRecordLogService shipSpeedRecordLogService;

    @Autowired
    private IHeartRateCountService heartRateCountService;

    @Autowired
    private ITrainingGroupChannelService trainingGroupChannelService;

    /**
     * 查询船速仪历史数据列表
     */
    @Override
    public List<ShipSpeedRecord> selectShipSpeedRecordList(ShipSpeedRecord shipSpeedRecord) {
        List<ShipSpeedRecord> list = new ArrayList<>();
        if(shipSpeedRecord!=null && shipSpeedRecord.getSegmentId()!=0 ){
            ShipSpeedRecord ss = selectShipSpeedRecord(shipSpeedRecord);
            list.add(ss);
        }else{
            list = shipSpeedRecordMapper.selectShipSpeedRecordList(shipSpeedRecord);
        }
        return list;
    }

    @Override
    public ShipSpeedRecord selectShipSpeedRecord(ShipSpeedRecord shipSpeedRecord) {
        ShipSpeedRecord ret = new ShipSpeedRecord();
        ret.setTotalTime(0.0d);
        ret.setTotalDistance(0.0d);
        ret.setSegmentId(0);
        ret.setStraightLineDistance(0.0d);
        ret.setDatajson("");
        ret.setDatajsonPropellerFrequency("");
        List<ShipSpeedRecord> list = shipSpeedRecordMapper.selectShipSpeedRecordList(shipSpeedRecord);
        if(list!=null && list.size()>0){
            for(ShipSpeedRecord ship : list){
                ret.setTotalTime(ret.getTotalTime()+ship.getTotalTime());
                ret.setTotalDistance(ret.getTotalDistance()+ship.getTotalDistance());
                ret.setStraightLineDistance(ret.getStraightLineDistance()+ship.getStraightLineDistance());
                String dataJson = ret.getDatajson()+ship.getDatajson();
                ret.setDatajson(dataJson.replace("][",","));
            }
            ret.setDatajsonPropellerFrequency(list.get(0).getDatajsonPropellerFrequency());
        }
        return ret;
    }

    @Override
    public List<PropellerFrequencyData> getPropellerFrequencyData(ShipSpeedRecord shipSpeedRecord) {
        List<PropellerFrequencyData> ret = new ArrayList<>();
        List<RealTimeDataVo> dataVos = shipSpeedRecordLogService.selectDataListByChannelId(shipSpeedRecord.getChannelId());
        int count = 4;
        return getPropellerFrequencyData(dataVos,count);
    }

    /**
     *
     * @param dataVos
     * @param count 一次桨频算一次平均桨频
     * @return
     */
    private List<PropellerFrequencyData> getPropellerFrequencyData(List<RealTimeDataVo> dataVos, int count) {
        List<PropellerFrequencyDataVo>  list = getImportantPoint(dataVos);
        List<PropellerFrequencyData> ret = new ArrayList<>();

        for(int i=0;i<list.size();i++){
            PropellerFrequencyData data = new PropellerFrequencyData();
            data.setCount(count);
            if(list.get(i).getType()==-1){
                data.setStartTime(list.get(i).getRealTime());
                if((i+count*2)<list.size()){
                    data.setDistanceTotal(list.get(i+count*2).getDistanceTotal());
                    data.setDistance(list.get(i+count*2).getDistanceTotal()-list.get(i).getDistanceTotal());
                    data.setEndTime(list.get(i+count*2).getRealTime());
                    double minute =  (getTime(data.getEndTime()) - getTime(data.getStartTime()))/1000;
                    data.setAveragePropeller(count/(minute/60.0));
                }else{
                    PropellerFrequencyDataVo temp = (i+count*2)<=list.size() ? list.get(i+count) : list.get(i);
                    data.setEndTime(temp.getRealTime());
                    data.setDistanceTotal(temp.getDistanceTotal());
                    data.setDistance(temp.getDistanceTotal()-list.get(i).getDistanceTotal());
                    double minute =  (getTime(data.getEndTime()) - getTime(data.getStartTime()))/60000;
                    double averagePropeller = minute!=0 ? 1/minute : 0.0;
                    data.setAveragePropeller(averagePropeller);
                }
                data.setRealTime(data.getEndTime());

                ret.add(data);
            }
        }
        return ret;
    }

    /**
     * 获取时间戳
     * @param utc
     * @return
     */
    private long getTime(String utc){
        Date dateTime = DateUtils.dateTime("HH:mm:ss.SSS",utc);
        return dateTime.getTime();
    }

    @Override
    public void addShipSpeedRecord(String shipSpeedId, Integer channelId) {
        //查询所有分段
        int segmentId = 0;
        ShipSpeedRecordLog params = new ShipSpeedRecordLog();
        params.setShipSpeedSn(shipSpeedId);
        params.setChannelId(channelId);
        List<ShipSpeedRecordLog> logs = shipSpeedRecordLogService.selectShipSpeedRecordLogList(params);
        if(logs!=null && logs.size()==0){
            return;
        }
        Date utc = DateUtils.dateTime("yyyy-MM-dd HHmmss.SSS","2020-02-01 "+logs.get(0).getUtc()+"0");
        long fristTime =  utc.getTime();

        List<HeartRateCount> heartRateCounts = heartRateCountService.qryCountByChannel(channelId);
        Double averageSpeed = 0.0;  //全程平均船速
        Double maxSpeed = 0.0;  //全程最大船速
        String sectionalSpeed = "";  //分段船速

        Double averageFrequency = 0.0;  //全程平均浆频
        int pulpNumber = 0;  //全程总浆数
        String propellerFrequencyTemp = "";  //分段浆频
        DecimalFormat  df  = new DecimalFormat("######0.00");


        if(heartRateCounts!=null && heartRateCounts.size()>0){
            long startTime = fristTime;
            boolean flagDatajsonPropellerFrequency = true;
            for(HeartRateCount heart : heartRateCounts){
                long endTime = fristTime + getLongTime(heart.getPointAchievement());
                List<ShipSpeedRecordLog> logTemp = getLogsByTime(logs,startTime,endTime);
                ShipSpeedRecord shipSpeedRecord = addShipSpeedRecord(logTemp,shipSpeedId,channelId,heart.getId());
                pulpNumber += shipSpeedRecord.getPropellerFrequency();

                if(flagDatajsonPropellerFrequency){
                    List<PropellerFrequencyData> propellerFrequencyDataList = getPropellerFrequencyData(ShipSpeedRecordLog.getRealTimeData(logs),4);
                    shipSpeedRecord.setDatajsonPropellerFrequency(JSONArray.toJSONString(propellerFrequencyDataList));
                    shipSpeedRecordMapper.updateById(shipSpeedRecord);
                    flagDatajsonPropellerFrequency = false;
                }
                //更新一下 HeartRateCount
                double timeInterval = (endTime-startTime)/1000d;
                heart.setShipSpeed(shipSpeedRecord.getTotalTime()==0? 0 : shipSpeedRecord.getTotalDistance()/timeInterval);
                heart.setShipSpeedId(shipSpeedRecord.getShipSpeedId());
                heart.setTotalDistance(shipSpeedRecord.getTotalDistance());
                double propellerFrequency = shipSpeedRecord.getPropellerFrequency()/(timeInterval/60);
                averageFrequency += propellerFrequency;
                heart.setPropellerFrequency(Math.round(propellerFrequency)+"");

                propellerFrequencyTemp += heart.getPropellerFrequency() + " ";

                sectionalSpeed += df.format(heart.getShipSpeed()) + " ";
                averageSpeed += heart.getShipSpeed();

                if(heart.getShipSpeed() > maxSpeed){
                    maxSpeed = heart.getShipSpeed();
                }

                heartRateCountService.updateById(heart);
                startTime = endTime;
            }
        }else{
            addShipSpeedRecord(logs,shipSpeedId,channelId,segmentId);
        }

        //同步航道的信息
        TrainingGroupChannel trainingGroupChannel = trainingGroupChannelService.getById(channelId);
        trainingGroupChannel.setAverageSpeed(heartRateCounts!=null ? df.format(averageSpeed/heartRateCounts.size())+"" : "0");
        trainingGroupChannel.setMaxSpeed(df.format(maxSpeed));
        trainingGroupChannel.setSectionalSpeed(sectionalSpeed.trim());
        trainingGroupChannel.setAverageFrequency(averageFrequency/heartRateCounts.size());
        trainingGroupChannel.setPulpNumber(pulpNumber);
        trainingGroupChannel.setPropellerFrequency(propellerFrequencyTemp.trim());
        trainingGroupChannelService.updateById(trainingGroupChannel);
    }

    private ShipSpeedRecord addShipSpeedRecord(List<ShipSpeedRecordLog> logs, String shipSpeedId, Integer channelId, int segmentId) {
        List<RealTimeDataVo> dataVos = ShipSpeedRecordLog.getRealTimeData(logs);

        ShipSpeedRecord shipSpeedRecord = new ShipSpeedRecord();
        shipSpeedRecord.setDatajsonPropellerFrequency("");
        if(dataVos==null || dataVos.size()==0){
            shipSpeedRecord.setTotalTime(0.0);
            shipSpeedRecord.setSegmentId(segmentId);
            shipSpeedRecord.setChannelId(channelId);
            shipSpeedRecord.setShipSpeedId(shipSpeedId);
            shipSpeedRecord.setDatajson("[]");
            shipSpeedRecord.setTotalDistance(0.0);
            shipSpeedRecord.setStraightLineDistance(0.0);
            shipSpeedRecord.setTotalTime(1.0);
            shipSpeedRecord.setPropellerFrequency(getPropellerFrequency(dataVos));
            return shipSpeedRecord;
        }
        RealTimeDataVo last = dataVos.get(dataVos.size()-1);

        shipSpeedRecord.setSegmentId(segmentId);
        shipSpeedRecord.setChannelId(channelId);
        shipSpeedRecord.setShipSpeedId(shipSpeedId);
        shipSpeedRecord.setCtime(new Date());
        shipSpeedRecord.setDatajson(JSONArray.toJSONString(dataVos));
        shipSpeedRecord.setTotalDistance(last.getDistanceTotal());
        shipSpeedRecord.setStraightLineDistance(last.getStraightLineDistance());
        shipSpeedRecord.setTotalTime(last.getTime());
        shipSpeedRecord.setPropellerFrequency(getPropellerFrequency(dataVos));
        shipSpeedRecordMapper.insert(shipSpeedRecord);
        return shipSpeedRecord;
    }

    /**
     * 获取指定时间区域的数据
     * @param logs
     * @param startTime
     * @param endTime
     * @return
     */
    private List<ShipSpeedRecordLog> getLogsByTime(List<ShipSpeedRecordLog> logs, long startTime, long endTime){
        List<ShipSpeedRecordLog> logsTemp = new ArrayList<>();
        ShipSpeedRecordLog prev = null;
        boolean prevAddFalg = false;
        for(ShipSpeedRecordLog shipSpeedRecordLog : logs){
            long time = DateUtils.dateTime("yyyy-MM-dd HHmmss.SSS","2020-02-01 "+shipSpeedRecordLog.getUtc()+"0").getTime();
            if(startTime<=time && endTime>time){
                if(prev!=null && !prevAddFalg){
                    //添加上一个节点
                    logsTemp.add(prev);
                    prevAddFalg = true;
                }
                logsTemp.add(shipSpeedRecordLog);
            }
            if(!prevAddFalg) prev = shipSpeedRecordLog;
        }
        return logsTemp;
    }

    /**
     * 00:00:26.60 转化成毫秒
     * @param strTime
     * @return
     */
    private static long getLongTime(String strTime){
        if(StringUtils.isEmpty(strTime)){
            return 0;
        }
        String[] ss = strTime.split("\\.");
        String[] as =ss[0].split(":");
        long longTime = (Integer.parseInt(as[0])*60*60 + Integer.parseInt(as[1])*60 + Integer.parseInt(as[2]))*1000+Integer.parseInt(ss[1])*10;
        return longTime;
    }

    /**
     * 根据速度曲线计算桨频
     * @param dataVos
     * @return
     */
    private int getPropellerFrequency(List<RealTimeDataVo> dataVos){
        List<Double> distances = new ArrayList<>();
        for(RealTimeDataVo realTimeDataVo : dataVos){
            distances.add(realTimeDataVo.getDistance());
        }
        return DataAnalysisUtils.getPeakNumPlus(distances);
    }

    /**
     * 获取波峰波谷
     * @param dataVos
     * @return
     */
    private List<PropellerFrequencyDataVo> getImportantPoint(List<RealTimeDataVo> dataVos){
        List<PropellerFrequencyDataVo> dataVoList = new ArrayList<>();

        List<Double> distances = new ArrayList<>();
        for(RealTimeDataVo realTimeDataVo : dataVos){
            distances.add(realTimeDataVo.getDistance());
        }
        double[] data = new double[dataVos.size()];
        int index = 0;
        for(Double aa : distances){
            data[index++] = aa;
        }
        int peak=0;

        try {
            int[] PeakAndTrough=new int[data.length];

            //需要三个不同的值进行比较，取lo,mid，hi分别为三值
            for (int lo=0,mid=1,hi=2;hi<data.length;hi++){
                //先令data[lo]不等于data[mid]
                while (mid<data.length&&data[mid]==data[lo]){
                    mid++;
                }

                hi=mid+1;

                //令data[hi]不等于data[mid]
                while (hi<data.length&&data[hi]==data[mid]){
                    hi++;
                }

                if (hi>=data.length){
                    break;
                }

                //检测是否为峰值
                if (data[mid]>data[lo]&&data[mid]>data[hi]){
                    PeakAndTrough[mid]=1;       //1代表波峰
                }else if(data[mid]<data[lo]&&data[mid]<data[hi]){
                    PeakAndTrough[mid]=-1;      //-1代表波谷
                }

                lo=mid;
                mid=hi;
            }

            //计算均值
            float ave=0;
            for (int i=0;i<data.length;i++){
                ave+=data[i];
            }
            ave/=data.length;

            //排除大于均值的波谷和小于均值的波峰
            for (int i=0;i<PeakAndTrough.length;i++){
                if ((PeakAndTrough[i]>0&&data[i]<ave)||(PeakAndTrough[i]<0&&data[i]>ave)){
                    PeakAndTrough[i]=0;
                }
            }

            //统计波谷数量
            for (int i=0;i<PeakAndTrough.length;i++){
                if(PeakAndTrough[i]!=0){
                    PropellerFrequencyDataVo vo = new PropellerFrequencyDataVo();
                    vo.setType(PeakAndTrough[i]);
                    vo.setRealTime(dataVos.get(i).getRealTime());
                    vo.setDistanceTotal(dataVos.get(i).getDistanceTotal());
                    dataVoList.add(vo);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataVoList;
    }
}